from coin.blockchain.web3.eth.native_private_client import \
    EthNativePrivateClient as nprivc
from coin.blockchain.web3.eth.constants import (
    ETH_TOKEN_TO_ADDRESS,
    BSC_TOKEN_TO_ADDRESS,
    TOKEN_TO_UNIT,
    NODE_SERVER
)
from web3.middleware import geth_poa_middleware
from coin.blockchain.request_util import (
    retry_error, parse_currency_balance, parse_coin_key)
from coin.exchange.base.kr_rest.private_client_base import \
    ExWalletPrivateClientBase


class EthPrivateClient(ExWalletPrivateClientBase):
  def __init__(self, *, blockchain_name, node_info=None, api_key=None):
    self._blockchain_name = blockchain_name
    self._token_unit = TOKEN_TO_UNIT
    node_info = node_info or NODE_SERVER[self._blockchain_name]
    self._nprivc = nprivc(node_info=node_info, api_key=api_key)
    if self._blockchain_name == 'ethereum':
      self._token_to_address = ETH_TOKEN_TO_ADDRESS
    elif self._blockchain_name == 'bsc':
      self._token_to_address = BSC_TOKEN_TO_ADDRESS
      self._nprivc._web3.middleware_onion.inject(geth_poa_middleware, layer=0)
    else:
      raise ValueError(self._blockchain_name)

  def _get_eth_balance(self, address, end_height):
    return self._nprivc.get_eth_balance(address, end_height)

  def get_token_balance(self, *, address, token_address, end_height):
    return self._nprivc.get_token_balance(address, token_address, end_height)

  def query_account_balance_impl(self, *, address, currency, end_height=None):
    token_address = self._token_to_address[currency]
    balance = retry_error(
      self.get_token_balance,
      address=address,
      token_address=token_address,
      end_height=end_height)
    balance = parse_currency_balance(
      currency, self._token_unit[currency], balance)
    return balance

  def get_latest_block_number_timestamp(self):
    return retry_error(self._nprivc.get_latest_block_number_timestamp)

  def get_block_timestamp(self, block_number):
    return retry_error(self._nprivc.get_block_timestamp, block_number=block_number)


if __name__ == '__main__':
  # bsc node
  key = parse_coin_key('../../coin_key/view/ledger02/hw_wallet/view_key.json')
  wallet_address = next(
    chain.access_key for chain in key.chain_keys if chain.blockchain == 'bsc')
  bsc_client = EthPrivateClient(
    node_info='https://red-dark-voice.bsc.quiknode.pro/c08980e1f26f6dbc6ff41ef2d46bc09a81b7b5e2/',
    blockchain_name='bsc')
  block_num, block_ts = bsc_client.get_latest_block_number_timestamp()
  print(bsc_client.query_account_balance_impl(address=wallet_address,
                                              currency='FNCY', end_height=block_num))
